package com.jzweb.springbootmail.service.impl;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.mail.Address;
import javax.mail.BodyPart;
import javax.mail.Flags;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.NoSuchProviderException;
import javax.mail.Part;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeUtility;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;

import com.jzweb.springbootmail.entity.User;
import com.jzweb.springbootmail.entity.User126Mail;
import com.jzweb.springbootmail.entity.User163Mail;
import com.jzweb.springbootmail.service.MailService;
import com.sun.mail.iap.ProtocolException;
import com.sun.mail.imap.IMAPFolder;
import com.sun.mail.imap.protocol.IMAPProtocol;

@Component
public class MailServiceImpl implements MailService {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
//    @Autowired
//    private JavaMailSender mailSender;

    private String from = "Ryan81@126.com ";
    
    private JavaMailSenderImpl initMailSender() {
    	User user = new User126Mail();
    	JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
    	mailSender.setUsername(user.getUsername());
    	mailSender.setPassword(user.getPassword());
    	mailSender.setHost(user.getSendHost());
    	mailSender.setPort(user.getSendPort());
    	mailSender.setProtocol(user.getSendProtocol());
    	return mailSender;
    }

//    @Override
//    public void sendSimpleMail(String to, String subject, String content) {
//    	JavaMailSenderImpl mailSender = initMailSender();
//        SimpleMailMessage message = new SimpleMailMessage();
//        message.setFrom(from);
//        message.setTo(to);
//        message.setSubject(subject);
//        message.setText(content);
//
//        try {
//            mailSender.send(message);
//            logger.info("简单邮件已经发送。");
//        } catch (Exception e) {
//            logger.error("发送简单邮件时发生异常！", e);
//        }
//    }

//    @Override
//    public void sendHtmlMail(String to, String subject, String content) {
//    	JavaMailSenderImpl mailSender = initMailSender();
//        MimeMessage message = mailSender.createMimeMessage();
//        try {
//            //true表示需要创建一个multipart message
//            MimeMessageHelper helper = new MimeMessageHelper(message, true);
//            helper.setFrom(from);
//            helper.setTo(to);
//            helper.setSubject(subject);
//            helper.setText(content, true);
//
//            mailSender.send(message);
//            logger.info("html邮件发送成功");
//        } catch (MessagingException e) {
//            logger.error("发送html邮件时发生异常！", e);
//        }
//    }

    @Override
    public void sendAttachmentsMail(String to, String subject, String content, List<String> filePaths) {
    	JavaMailSenderImpl mailSender = initMailSender();
        MimeMessage message = mailSender.createMimeMessage();
        try {
        	
        	//不加utf-8，中文会乱码
            MimeMessageHelper helper = new MimeMessageHelper(message, true,"utf-8");
            helper.setFrom(from);
            helper.setTo(to);
            helper.setSubject(subject);
            helper.setText(content, true);

            for(String str : filePaths) {
            	FileSystemResource file = new FileSystemResource(new File(str));
                String fileName = str.substring(str.lastIndexOf(File.separator));
                helper.addAttachment(fileName, file);
            }

            mailSender.send(message);
            logger.info("带附件的邮件已经发送。");
        } catch (MessagingException e) {
            logger.error("发送带附件的邮件时发生异常！", e);
        }
    }
    

	@Override
	public void receiveMail() {
		
		User user = new User126Mail();
		Properties props = new Properties(); 
        props.setProperty("mail.store.protocol", user.getReceiveProtocol()); 
        props.setProperty("mail.imap.host", user.getReceiveHost()); 
        props.setProperty("mail.imap.port", String.valueOf(user.getReceivePort())); 
     // 创建Session实例对象 
        Session session = Session.getInstance(props);
     // 创建IMAP协议的Store对象 
        Store store;
		try {
			store = session.getStore(user.getReceiveProtocol());
			store.connect(user.getUsername(), user.getPassword());
			
			Folder defaultFolder = store.getDefaultFolder();
			Folder[] folders = defaultFolder.list("INBOX"); //defaultFolder.list("*");
			for(Folder folder : folders) {
				IMAPFolder imapFolder = (IMAPFolder) folder;
				imapFolder.doCommand(new IMAPFolder.ProtocolCommand() {

					@Override
					public Object doCommand(IMAPProtocol protocol) throws ProtocolException {
						Map<String,String> gmap = new HashMap<>();
						gmap.put("GUID", "jzweb");
						protocol.id(gmap);
						return null;
					}
					
				});
				
				folder.open(Folder.READ_WRITE); 
				// 获得收件箱的未读邮件列表 
	            //Message[] messages = imapFolder.search(new FlagTerm(new Flags(Flags.Flag.SEEN), false));//imapFolder.getMessages(); 
				//获取收件箱的全部邮件列表
	            Message[] messages = imapFolder.getMessages(); 
	            
	            System.out.println("收件箱名称" + folder.getName() + "!"); 
	             
	            // 打印不同状态的邮件数量 
//	            System.out.println("收件箱中共" + messages.length + "封邮件!"); 
//	            System.out.println("收件箱中共" + folder.getUnreadMessageCount() + "封未读邮件!"); 
//	            System.out.println("收件箱中共" + folder.getNewMessageCount() + "封新邮件!"); 
//	            System.out.println("收件箱中共" + folder.getDeletedMessageCount() + "封已删除邮件!"); 
	             
	            System.out.println("------------------------开始解析邮件----------------------------------"); 
	            
	            int total = messages.length;
	            System.out.println("-----------------您的邮箱共有邮件：" + total + " 封--------------");
	            // 得到收件箱文件夹信息，获取邮件列表
	            //Message[] msgs = imapFolder.getMessages();
	            System.out.println("\t收件箱的总邮件数：" + messages.length);
	            for (int i = 0; i < total; i++) {
	                Message a = messages[i];
	                //   获取邮箱邮件名字及时间
	                
	                MimeMessage msg = (MimeMessage) a;
//	                MailBox mailBox = new MailBox();
//	                mailBox.mail(String.valueOf(imapFolder.getUID(msg)), msg);
//	                
//	                if(mailBox.isAttachFlag()) {
//	                	//有附件，需要收取
//	                }
	                
	                System.out.println("------------------解析第" + msg.getMessageNumber() + "封邮件-------------------- "); 
	                System.out.println("是否已读：" + isSeen(msg));  
	                System.out.println("ID: " + imapFolder.getUID(msg));  
	                System.out.println("主题: " + getSubject(msg));  
	                System.out.println("发件人: " + getFrom(msg));  
	                System.out.println("收件人：" + getReceiveAddress(msg, null));  
	                System.out.println("发送时间：" + getSentDate(msg, null));  
	                System.out.println("是否已读：" + isSeen(msg));  
	                System.out.println("邮件优先级：" + getPriority(msg));  
	                System.out.println("是否需要回执：" + isReplySign(msg));  
	                System.out.println("邮件大小：" + msg.getSize() * 1024 + "kb");  
	                boolean isContainerAttachment = isContainAttachment(msg);  
	                System.out.println("是否包含附件：" + isContainerAttachment);  
	                if (isContainerAttachment) {  
	                    saveAttachment(msg, "C:\\Users\\030998\\Desktop\\mailFile\\"+msg.getSubject() + "_"+i+"_"); //保存附件  
	                }   
	                StringBuffer content = new StringBuffer(30);  
	                getMailTextContent(msg, content);  
	                System.out.println("邮件正文：" + (content.length() > 1000 ? content.substring(0,1000) + "..." : content));  
	                System.out.println("------------------第" + msg.getMessageNumber() + "封邮件解析结束-------------------- ");  
	                System.out.println();   
	                //收取后，设成已读，下次就不收了
	                //msg.setFlag(Flags.Flag.SEEN, true);
	      
	            }
	            System.out.println("\t未读邮件数：" + folder.getUnreadMessageCount());
	            System.out.println("\t新邮件数：" + folder.getNewMessageCount());
	            System.out.println("----------------End------------------");
	            
	            
	             
	            // 关闭资源 
	            folder.close(false); 
			}
			
	        
            store.close(); 
            
            
		} catch (NoSuchProviderException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        
        
	}
	
	/**  
     * 保存附件  
     * @param part 邮件中多个组合体中的其中一个组合体  
     * @param destDir  附件保存目录  
     * @throws UnsupportedEncodingException  
     * @throws MessagingException  
     * @throws FileNotFoundException  
     * @throws IOException  
     */  
    public void saveAttachment(Part part, String destDir) throws UnsupportedEncodingException, MessagingException,  
            FileNotFoundException, IOException {  
        if (part.isMimeType("multipart/*")) {  
            Multipart multipart = (Multipart) part.getContent();    //复杂体邮件  
            //复杂体邮件包含多个邮件体  
            int partCount = multipart.getCount();  
            for (int i = 0; i < partCount; i++) {  
                //获得复杂体邮件中其中一个邮件体  
                BodyPart bodyPart = multipart.getBodyPart(i);  
                System.out.println("附件大小:  "+bodyPart.getSize());
                
                //某一个邮件体也有可能是由多个邮件体组成的复杂体  
                String disp = bodyPart.getDisposition();  
                if (disp != null && (disp.equalsIgnoreCase(Part.ATTACHMENT) || disp.equalsIgnoreCase(Part.INLINE))) {  
                    InputStream is = bodyPart.getInputStream();  
                    saveFile(is, destDir, decodeText(bodyPart.getFileName()));  
                } else if (bodyPart.isMimeType("multipart/*")) {  
                    saveAttachment(bodyPart,destDir);  
                } else {  
                    String contentType = bodyPart.getContentType();  
                    if (contentType.indexOf("name") != -1 || contentType.indexOf("application") != -1) {  
                        saveFile(bodyPart.getInputStream(), destDir, decodeText(bodyPart.getFileName()));  
                    }  
                }  
            }  
        } else if (part.isMimeType("message/rfc822")) {  
            saveAttachment((Part) part.getContent(),destDir);  
        }  
    }
    
    /**  
     * 读取输入流中的数据保存至指定目录  
     * @param is 输入流  
     * @param fileName 文件名  
     * @param destDir 文件存储目录  
     * @throws FileNotFoundException  
     * @throws IOException  
     */  
    private void saveFile(InputStream is, String destDir, String fileName)  
            throws FileNotFoundException, IOException {  
        BufferedInputStream bis = new BufferedInputStream(is);  
        BufferedOutputStream bos = new BufferedOutputStream(  
                new FileOutputStream(new File(destDir + fileName)));  
        int len = -1;  
        while ((len = bis.read()) != -1) {  
            bos.write(len);  
            bos.flush();  
        }  
        bos.close();  
        bis.close();  
    }
	
	/** 
     * 获得邮件的优先级 
     * @param msg 邮件内容 
     * @return 1(High):紧急  3:普通(Normal)  5:低(Low) 
     * @throws MessagingException  
     */  
    public static String getPriority(MimeMessage msg) throws MessagingException {  
        String priority = "普通";  
        String[] headers = msg.getHeader("X-Priority");  
        if (headers != null) {  
            String headerPriority = headers[0];  
            if (headerPriority.indexOf("1") != -1 || headerPriority.indexOf("High") != -1)  
                priority = "紧急";  
            else if (headerPriority.indexOf("5") != -1 || headerPriority.indexOf("Low") != -1)  
                priority = "低";  
            else  
                priority = "普通";  
        }  
        return priority;  
    }
    
    /** 
     * 获得邮件文本内容 
     * @param part 邮件体 
     * @param content 存储邮件文本内容的字符串 
     * @throws MessagingException 
     * @throws IOException 
     */  
    public static void getMailTextContent(Part part, StringBuffer content) throws MessagingException, IOException {  
        //如果是文本类型的附件，通过getContent方法可以取到文本内容，但这不是我们需要的结果，所以在这里要做判断  
    	
        boolean isContainTextAttach = part.getContentType().indexOf("name") > 0;   
        // text/html
        // text/plain
        if (/*part.isMimeType("text/*")*/ part.isMimeType("text/html")&& !isContainTextAttach) {  
            content.append(part.getContent().toString());
        } else if (part.isMimeType("message/rfc822")) {
            getMailTextContent((Part)part.getContent(),content);
        } else if (part.isMimeType("multipart/*")) {
            Multipart multipart = (Multipart) part.getContent();
            int partCount = multipart.getCount();
            for (int i = 0; i < partCount; i++) {
                BodyPart bodyPart = multipart.getBodyPart(i);
                getMailTextContent(bodyPart,content);
            }  
        }  
    }
    
    /** 
     * 判断邮件中是否包含附件 
     * @param msg 邮件内容 
     * @return 邮件中存在附件返回true，不存在返回false 
     * @throws MessagingException 
     * @throws IOException 
     */  
    public static boolean isContainAttachment(Part part) throws MessagingException, IOException {  
        boolean flag = false;  
        if (part.isMimeType("multipart/*")) {  
            MimeMultipart multipart = (MimeMultipart) part.getContent();  
            int partCount = multipart.getCount();  
            for (int i = 0; i < partCount; i++) {  
                BodyPart bodyPart = multipart.getBodyPart(i);  
                System.out.println("附件大小:  "+bodyPart.getSize());
                //后续修正：附件不要超过52428800(50M，包含大概27%冗余量)
                
                String type = bodyPart.getContentType().split(";")[0];
                
                
                
                
                String disp = bodyPart.getDisposition();  
                if (disp != null && (disp.equalsIgnoreCase(Part.ATTACHMENT) || disp.equalsIgnoreCase(Part.INLINE))) {  
                    flag = true;  
                } else if (bodyPart.isMimeType("multipart/*")) {  
                    flag = isContainAttachment(bodyPart);  
                } else {  
                    String contentType = bodyPart.getContentType();  
                    if (contentType.indexOf("application") != -1) {  
                        flag = true;  
                    }    
                      
                    if (contentType.indexOf("name") != -1) {  
                        flag = true;  
                    }   
                }  
                  
                if (flag) break;  
            }  
        } else if (part.isMimeType("message/rfc822")) {  
            flag = isContainAttachment((Part)part.getContent());  
        }  
        return flag;  
    }
	
	/**  
     * 判断邮件是否已读  
     * @param msg 邮件内容  
     * @return 如果邮件已读返回true,否则返回false  
     * @throws MessagingException   
     */  
    public static boolean isSeen(MimeMessage msg) throws MessagingException {  
        return msg.isSet(Flags.Flag.SEEN);  
    }
	
	public static String getSubject(MimeMessage msg) throws UnsupportedEncodingException, MessagingException {  
        return MimeUtility.decodeText(msg.getSubject());  
    }
	/** 
     * 判断邮件是否需要阅读回执 
     * @param msg 邮件内容 
     * @return 需要回执返回true,否则返回false 
     * @throws MessagingException 
     */  
    public static boolean isReplySign(MimeMessage msg) throws MessagingException {  
        boolean replySign = false;  
        String[] headers = msg.getHeader("Disposition-Notification-To");  
        if (headers != null)  
            replySign = true;  
        return replySign;  
    }
	public static String getFrom(MimeMessage msg) throws MessagingException, UnsupportedEncodingException {  
        String from = "";  
        Address[] froms = msg.getFrom();  
        if (froms.length < 1)  
            throw new MessagingException("没有发件人!");  
          
        InternetAddress address = (InternetAddress) froms[0];  
        String person = address.getPersonal();  
        if (person != null) {  
            person = MimeUtility.decodeText(person) + " ";  
        } else {  
            person = "";  
        }  
        from = person + "<" + address.getAddress() + ">";  
          
        return from;  
    } 
	
	/** 
     * 根据收件人类型，获取邮件收件人、抄送和密送地址。如果收件人类型为空，则获得所有的收件人 
     * <p>Message.RecipientType.TO  收件人</p> 
     * <p>Message.RecipientType.CC  抄送</p> 
     * <p>Message.RecipientType.BCC 密送</p> 
     * @param msg 邮件内容 
     * @param type 收件人类型 
     * @return 收件人1 <邮件地址1>, 收件人2 <邮件地址2>, ... 
     * @throws MessagingException 
     */  
    public static String getReceiveAddress(MimeMessage msg, Message.RecipientType type) throws MessagingException {  
        StringBuffer receiveAddress = new StringBuffer();  
        Address[] addresss = null;  
        if (type == null) {  
            addresss = msg.getAllRecipients();  
        } else {  
            addresss = msg.getRecipients(type);  
        }  
          
        if (addresss == null || addresss.length < 1)  
            throw new MessagingException("没有收件人!");  
        for (Address address : addresss) {  
            InternetAddress internetAddress = (InternetAddress)address;  
            receiveAddress.append(internetAddress.toUnicodeString()).append(",");  
        }  
          
        receiveAddress.deleteCharAt(receiveAddress.length()-1); //删除最后一个逗号  
          
        return receiveAddress.toString();  
    }
    
    /** 
     * 获得邮件发送时间 
     * @param msg 邮件内容 
     * @return yyyy年mm月dd日 星期X HH:mm 
     * @throws MessagingException 
     */  
    public static String getSentDate(MimeMessage msg, String pattern) throws MessagingException {  
        Date receivedDate = msg.getSentDate();  
        if (receivedDate == null)  
            return "";  
          
        if (pattern == null || "".equals(pattern))  
            pattern = "yyyy年MM月dd日 E HH:mm ";  
          
        return new SimpleDateFormat(pattern).format(receivedDate);  
    }
    
    public String decodeText(String encodeText) throws UnsupportedEncodingException {  
        if (encodeText == null || "".equals(encodeText)) {  
            return "";  
        } else {  
            return MimeUtility.decodeText(encodeText);  
        }  
    }
    
    @Override
    public void deleteMail(long[] uids) {
    	User user = new User163Mail();
    	
    	Properties props = new Properties(); 
        props.setProperty("mail.store.protocol", "imap"); 
        props.setProperty("mail.imap.host", "imap.126.com"); 
        props.setProperty("mail.imap.port", "143"); 
     // 创建Session实例对象 
        Session session = Session.getInstance(props);
     // 创建IMAP协议的Store对象 
        Store store;
        try {
        	store = session.getStore("imap");
			store.connect(user.getUsername(), user.getPassword());
			
			Folder defaultFolder = store.getDefaultFolder();
			Folder[] folders = defaultFolder.list("INBOX"); //defaultFolder.list("*");
			for(Folder folder : folders) {
				IMAPFolder imapFolder = (IMAPFolder) folder;
				imapFolder.doCommand(new IMAPFolder.ProtocolCommand() {

					@Override
					public Object doCommand(IMAPProtocol protocol) throws ProtocolException {
						Map<String,String> gmap = new HashMap<>();
						gmap.put("GUID", "jzweb");
						protocol.id(gmap);
						return null;
					}
					
				});
				
				folder.open(Folder.READ_WRITE); 
				// 获得收件箱的邮件列表 
	            Message[] messages = imapFolder.getMessagesByUID(uids); 
	            
	            if (messages == null || messages.length < 1) {
	                throw new MessagingException("未找到要解析的邮件!");
	            }
	            // 解析所有邮件
	            for (int i = 0, count = messages.length; i < count; i++) {

	                // 邮件删除
	                Message message = messages[i];
	                String subject = message.getSubject();
	                // set the DELETE flag to true
	                message.setFlag(Flags.Flag.DELETED, true);
	                System.out.println("Marked DELETE for message: " + subject);

	            }
	            
	         // 释放资源
			folder.close(true);
			}
			
	        store.close();
        }catch(Exception e) {
        	
        }
    }
	
	
}
